import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class FileEncryptorGUI extends JFrame {
    private static final String ALGORITHM = "AES";
    private SecretKeySpec secretKey;
    private byte[] key;

    // GUI组件
    private JTextField filePathField;
    private JPasswordField passwordField;
    private JRadioButton encryptRadio;
    private JRadioButton decryptRadio;
    private JCheckBox replaceOriginalCheck;
    private JButton selectFileButton;
    private JButton processButton;
    private JProgressBar progressBar;
    private JTextArea statusArea;
    private JLabel speedLabel;

    // 用于大文件处理的变量
    private static final int BUFFER_SIZE = 8192; // 8KB缓冲区，适合大文件
    private long totalBytes;
    private long processedBytes;
    private long startTime;

    public FileEncryptorGUI() {
        initializeUI();
        setupListeners();
        setTitle("文件加密解密工具");
        setSize(600, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null); // 居中显示
    }

    private void initializeUI() {
        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        // 输入面板
        JPanel inputPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;

        // 文件路径
        gbc.gridx = 0;
        gbc.gridy = 0;
        inputPanel.add(new JLabel("文件路径:"), gbc);

        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        filePathField = new JTextField(30);
        inputPanel.add(filePathField, gbc);

        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.fill = GridBagConstraints.NONE;
        gbc.weightx = 0;
        selectFileButton = new JButton("浏览...");
        inputPanel.add(selectFileButton, gbc);

        // 密码
        gbc.gridx = 0;
        gbc.gridy = 1;
        inputPanel.add(new JLabel("密钥:"), gbc);

        gbc.gridx = 1;
        gbc.gridy = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        passwordField = new JPasswordField(30);
        inputPanel.add(passwordField, gbc);

        // 操作类型
        gbc.gridx = 0;
        gbc.gridy = 2;
        inputPanel.add(new JLabel("操作类型:"), gbc);

        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.fill = GridBagConstraints.NONE;
        JPanel radioPanel = new JPanel();
        encryptRadio = new JRadioButton("加密");
        decryptRadio = new JRadioButton("解密");
        ButtonGroup group = new ButtonGroup();
        group.add(encryptRadio);
        group.add(decryptRadio);
        encryptRadio.setSelected(true);
        radioPanel.add(encryptRadio);
        radioPanel.add(decryptRadio);
        inputPanel.add(radioPanel, gbc);

        // 替换原文件选项
        gbc.gridx = 0;
        gbc.gridy = 3;
        inputPanel.add(new JLabel("选项:"), gbc);

        gbc.gridx = 1;
        gbc.gridy = 3;
        replaceOriginalCheck = new JCheckBox("处理后替换原文件");
        inputPanel.add(replaceOriginalCheck, gbc);

        mainPanel.add(inputPanel, BorderLayout.NORTH);

        // 状态区域
        JPanel statusPanel = new JPanel(new BorderLayout(5, 5));
        statusArea = new JTextArea(8, 40);
        statusArea.setEditable(false);
        statusArea.setBorder(BorderFactory.createTitledBorder("状态信息"));
        statusPanel.add(new JScrollPane(statusArea), BorderLayout.CENTER);

        // 进度条
        JPanel progressPanel = new JPanel(new BorderLayout(5, 5));
        progressBar = new JProgressBar(0, 100);
        progressBar.setStringPainted(true);
        speedLabel = new JLabel("速度: -- MB/s");
        progressPanel.add(progressBar, BorderLayout.CENTER);
        progressPanel.add(speedLabel, BorderLayout.EAST);

        statusPanel.add(progressPanel, BorderLayout.SOUTH);

        mainPanel.add(statusPanel, BorderLayout.CENTER);

// 处理按钮
        processButton = new JButton("开始处理");
// 使用支持中文的字体
        processButton.setFont(new Font("SimHei", Font.BOLD, 14)); // 黑体
// 或者使用 "Microsoft YaHei"（微软雅黑）
// processButton.setFont(new Font("Microsoft YaHei", Font.BOLD, 14));
        processButton.setPreferredSize(new Dimension(0, 40));
        mainPanel.add(processButton, BorderLayout.SOUTH);
        add(mainPanel);
    }

    private void setupListeners() {
        // 选择文件按钮
        selectFileButton.addActionListener(e -> {
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            int result = fileChooser.showOpenDialog(FileEncryptorGUI.this);
            if (result == JFileChooser.APPROVE_OPTION) {
                File selectedFile = fileChooser.getSelectedFile();
                filePathField.setText(selectedFile.getAbsolutePath());
            }
        });

        // 处理按钮
        processButton.addActionListener(e -> {
            String filePath = filePathField.getText().trim();
            String password = new String(passwordField.getPassword());
            boolean isEncrypt = encryptRadio.isSelected();
            boolean replaceOriginal = replaceOriginalCheck.isSelected();

            // 验证输入
            if (filePath.isEmpty()) {
                JOptionPane.showMessageDialog(FileEncryptorGUI.this,
                        "请选择要处理的文件", "输入错误", JOptionPane.ERROR_MESSAGE);
                return;
            }

            if (password.isEmpty()) {
                JOptionPane.showMessageDialog(FileEncryptorGUI.this,
                        "请输入密钥", "输入错误", JOptionPane.ERROR_MESSAGE);
                return;
            }

            File file = new File(filePath);
            if (!file.exists() || !file.isFile()) {
                JOptionPane.showMessageDialog(FileEncryptorGUI.this,
                        "选择的文件不存在", "文件错误", JOptionPane.ERROR_MESSAGE);
                return;
            }

            // 开始处理（在单独线程中执行，避免UI冻结）
            new Thread(() -> {
                try {
                    setKey(password);
                    statusArea.append("开始" + (isEncrypt ? "加密" : "解密") + "...\n");
                    statusArea.append("文件: " + filePath + "\n");
                    processButton.setEnabled(false);
                    selectFileButton.setEnabled(false);

                    if (isEncrypt) {
                        encryptFile(file, replaceOriginal);
                    } else {
                        decryptFile(file, replaceOriginal);
                    }
                } catch (Exception ex) {
                    statusArea.append("处理错误: " + ex.getMessage() + "\n");
                    ex.printStackTrace();
                } finally {
                    processButton.setEnabled(true);
                    selectFileButton.setEnabled(true);
                }
            }).start();
        });
    }

    // 设置加密密钥
    private void setKey(String myKey) {
        try {
            key = myKey.getBytes(StandardCharsets.UTF_8);
            MessageDigest sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16); // 使用前16字节，适合AES-128
            secretKey = new SecretKeySpec(key, ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            statusArea.append("密钥处理错误: " + e.getMessage() + "\n");
            e.printStackTrace();
        }
    }

    // 加密文件
    private void encryptFile(File inputFile, boolean replaceOriginal) {
        try {
            totalBytes = inputFile.length();
            processedBytes = 0;
            startTime = System.currentTimeMillis();

            String tempFilePath = inputFile.getAbsolutePath() + ".encrypted.tmp";
            File tempFile = new File(tempFilePath);

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            try (FileInputStream in = new FileInputStream(inputFile);
                 FileOutputStream out = new FileOutputStream(tempFile);
                 CipherOutputStream cipherOut = new CipherOutputStream(out, cipher)) {

                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;

                while ((bytesRead = in.read(buffer)) != -1) {
                    cipherOut.write(buffer, 0, bytesRead);
                    processedBytes += bytesRead;
                    updateProgress();
                }
            }

            completeProcessing(tempFile, inputFile, replaceOriginal, "加密");
        } catch (Exception e) {
            statusArea.append("加密错误: " + e.getMessage() + "\n");
            e.printStackTrace();
        }
    }

    // 解密文件
    private void decryptFile(File inputFile, boolean replaceOriginal) {
        try {
            totalBytes = inputFile.length();
            processedBytes = 0;
            startTime = System.currentTimeMillis();

            String tempFilePath = inputFile.getAbsolutePath() + ".decrypted.tmp";
            File tempFile = new File(tempFilePath);

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);

            try (FileInputStream in = new FileInputStream(inputFile);
                 CipherInputStream cipherIn = new CipherInputStream(in, cipher);
                 FileOutputStream out = new FileOutputStream(tempFile)) {

                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;

                while ((bytesRead = cipherIn.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                    processedBytes += bytesRead;
                    updateProgress();
                }
            }

            completeProcessing(tempFile, inputFile, replaceOriginal, "解密");
        } catch (Exception e) {
            statusArea.append("解密错误: " + e.getMessage() + "\n");
            e.printStackTrace();
        }
    }

    // 完成处理并替换文件（如果需要）
    private void completeProcessing(File tempFile, File originalFile,
                                    boolean replaceOriginal, String operation) {
        try {
            if (replaceOriginal) {
                // 先删除原文件
                if (originalFile.delete()) {
                    // 重命名临时文件
                    if (tempFile.renameTo(originalFile)) {
                        statusArea.append(operation + "成功，已替换原文件\n");
                    } else {
                        statusArea.append(operation + "成功，但无法替换原文件\n");
                        statusArea.append("处理后的文件保存在: " + tempFile.getAbsolutePath() + "\n");
                    }
                } else {
                    statusArea.append(operation + "成功，但无法删除原文件\n");
                    statusArea.append("处理后的文件保存在: " + tempFile.getAbsolutePath() + "\n");
                }
            } else {
                String destPath = originalFile.getAbsolutePath() + "." +
                        (operation.equals("加密") ? "encrypted" : "decrypted");
                File destFile = new File(destPath);

                // 如果目标文件已存在，删除它
                if (destFile.exists() && !destFile.delete()) {
                    statusArea.append("目标文件已存在且无法替换\n");
                    return;
                }

                if (tempFile.renameTo(destFile)) {
                    statusArea.append(operation + "成功\n");
                    statusArea.append("处理后的文件保存在: " + destFile.getAbsolutePath() + "\n");
                } else {
                    statusArea.append(operation + "成功，但无法保存处理后的文件\n");
                    statusArea.append("临时文件位置: " + tempFile.getAbsolutePath() + "\n");
                }
            }
        } catch (Exception e) {
            statusArea.append("处理文件时出错: " + e.getMessage() + "\n");
        } finally {
            // 重置进度条
            SwingUtilities.invokeLater(() -> {
                progressBar.setValue(0);
                speedLabel.setText("速度: -- MB/s");
            });
        }
    }

    // 更新进度条和状态
    private void updateProgress() {
        if (totalBytes <= 0) return;

        int progress = (int) ((processedBytes * 100) / totalBytes);

        // 计算处理速度 (MB/s)
        long elapsedTime = (System.currentTimeMillis() - startTime) / 1000; // 秒
        if (elapsedTime > 0) {
            double speedMBps = (processedBytes / (1024.0 * 1024.0)) / elapsedTime;
            String speedText = String.format("速度: %.2f MB/s", speedMBps);

            SwingUtilities.invokeLater(() -> {
                speedLabel.setText(speedText);
            });
        }

        // 在EDT线程中更新UI组件
        SwingUtilities.invokeLater(() -> {
            progressBar.setValue(progress);
            progressBar.setString(progress + "%");
        });
    }

    public static void main(String[] args) {
        // 在EDT线程中启动UI
        SwingUtilities.invokeLater(() -> {
            new FileEncryptorGUI().setVisible(true);
        });
    }
}
    